import time
from typing import Any

from sqlalchemy.exc import IntegrityError
from sqlmodel import SQLModel, Field, Session, select, func, or_

from settings import auto_session


class NameCard(SQLModel, table = True):
    __tablename__ = 'namecard'

    id:int = Field(primary_key=True, default=None)
    name:str
    institution:str
    position:str
    sex:str
    phone:str
    email:str
    address:str
    weixinid:str
    birthday:int = Field(default = 0)
    isinrecycle:bool = Field(nullable = False, default = False)
    createtime:int = Field(nullable=False)
    holder_id:int = Field(nullable=False, foreign_key="namecardholder.id", ondelete="CASCADE")
    def __init__(self, holder_id:int, isinrecycle:bool = False, **kwargs):
        """
        初始化NameCard对象。

        参数:
            id (int): 名片ID，默认为0。
            name (str): 姓名，默认为空字符串。
            institution (str): 机构名称，默认为空字符串。
            position (str): 职位，默认为空字符串。
            sex (str): 性别，默认为空字符串。
            phone (str): 电话，默认为空字符串。
            email (str): 邮箱，默认为空字符串。
            address (str): 地址，默认为空字符串。
            weixinid (str): 微信号，默认为字符串。
            birthday (int): 出生年月日，默认为数字，格式为yyyymmdd，如20010321。
        """
        kwargs["holder_id"] = holder_id
        kwargs["isinrecycle"] = isinrecycle
        kwargs["createtime"] = int(time.time())
        super().__init__(**kwargs)
    def to_dict(self)->dict:
        return self.model_dump()

@auto_session
def search_some_namecard_from_id_in_holder(holder_id: int,
                                           cardids: list[int], isinrecycle: bool = False,
                                           session:Session = None) -> list[dict[str, Any]] | None:
    """
    根据ID列表查询多个名片信息。

    参数:
        user_id (int): 用户账号。
        holdername (str): 名片夹名称。
        cardids (list[int]): 名片ID列表。

    返回:
        list[dict[str, Any]] | None: 包含多个名片信息的NameCard对象列表，未找到时返回空列表，数据库错误时返回None。
    """
    stmt = select(NameCard).where(NameCard.id.in_(cardids), NameCard.holder_id == holder_id,
                                  NameCard.isinrecycle == isinrecycle)
    namecards = session.exec(stmt)
    ret = [n.to_dict() for n in namecards]
    return ret

@auto_session
def search_some_namecard_from_id(cardids: list[int], isinrecycle: bool = False,
                                session:Session = None) -> list[dict[str, Any]] | None:
    """
    根据ID列表查询多个名片信息。

    参数:
        cardids (list[int]): 名片ID列表。

    返回:
        list[dict[str, Any]] | None: 包含多个名片信息的NameCard对象列表，未找到时返回空列表，数据库错误时返回None。
    """
    stmt = select(NameCard).where(NameCard.id.in_(cardids),
                                  NameCard.isinrecycle == isinrecycle)
    namecards = session.exec(stmt)
    ret = [n.to_dict() for n in namecards]
    return ret

@auto_session
def search_all_namecard_in_holder(holder_id: int, isinrecycle: bool = False, session:Session = None) -> list[dict[str, Any]] | None:
    """
    查询数据库中的所有名片信息。

    参数:
        user_id (int): 用户账号。
        holder_id (int): 名片夹名称。

    返回:
        list[dict[str, Any]] | None: 包含多个名片信息的NameCard对象列表，未找到时返回空列表，数据库错误时返回None。

    异常:
        sqlite3.Error: 数据库操作出错时引发。
    """
    stmt = select(NameCard).where(NameCard.holder_id == holder_id , NameCard.isinrecycle == isinrecycle)
    namecards = session.exec(stmt).all()
    ret = [n.to_dict() for n in namecards]
    return ret

@auto_session
def count_namecard_in_holder(holder_id: int, isinrecycle:bool = False, session:Session = None) -> int | None:
    """
    统计某个名片夹中的名片数量
    参数:
        holder_id (int): 名片夹名称。

    返回:
        int | None: 包含多个名片信息的NameCard对象列表，未找到时返回空列表，数据库错误时返回None。

    异常:
        sqlite3.Error: 数据库操作出错时引发。
    """
    stmt = select(func.count()).where(
        NameCard.holder_id == holder_id,
        NameCard.isinrecycle == isinrecycle
    )

    # 直接使用 scalar() 获取计数结果
    count = session.scalars(stmt).first()
    return count or 0  # 如果没有记录，返回0

@auto_session
def insert_1_namecard(namecard: NameCard, session:Session = None) -> int | None:
    """
    插入单条名片记录到数据库，并返回新插入的ID。

    参数:
        user_id (int): 用户账号。
        holder_id (int): 名片夹ID。
        namecard (NameCard): 包含联系人信息的 NameCard 对象。

    返回:
        int | None: 成功插入时返回新名片的ID，数据库操作失败时返回None，名片夹不存在时返回-1。
    """
    session.add(namecard)
    try:
        session.commit()
        return namecard.id
    except IntegrityError as e:
        session.rollback()
        print(f"插入数据时出错: {e}")
        return -2

@auto_session
def insert_some_namecard(namecards: list[NameCard], session:Session = None) -> int | None:
    """
    批量插入多条名片记录到数据库，并返回成功插入的记录数。

    参数:
        user_id (int): 用户账号。
        holdername (int): 名片夹名。
        namecards (list[NameCard]): 包含多条联系人信息的列表，每个元素是 NameCard 对象。

    返回:
        int | None: 成功插入的记录数，名片夹不存在时返回-1，数据库操作失败时返回None。

    异常:
        sqlite3.Error: 数据库操作出错时引发。
        ValueError: 联系人信息字段不完整时引发。
    """
    success_count = 0
    for n in namecards:
        if insert_1_namecard(namecard=n, session=session) or 0 > 0:
            success_count += 1
    return success_count

@auto_session
def update_1_namecard(namecard: NameCard, session:Session = None) -> int | None:
    """
    修改单张名片。

    参数:
        user_id (int): 用户账号。
        holder_id (int): 名片夹ID。
        namecard (NameCard): 包含完整名片信息的 NameCard 对象。

    返回:
        int | None: 1表示名片夹不存在，2表示名片不存在，0表示修改成功，None表示数据库出错。
    """
    if not search_some_namecard_from_id_in_holder(holder_id= namecard.holder_id, cardids=[namecard.id],
                                                  isinrecycle= namecard.isinrecycle, session=session):
        return 2
    try:
        session.merge(namecard)
        session.commit()
        return 0
    except IntegrityError as e:
        session.rollback()
        print(f"修改数据时出错: {e}")
        return None

@auto_session
def recycle_1_namecard(namecard_id: int, session:Session = None) -> int | None:
    """
    将单张名片放入回收站。

    参数:
        user_id (int): 用户账号。
        holder_id (int): 名片夹ID。
    返回:
        int | None: 1表示名片夹不存在，2表示名片不存在，0表示修改成功，None表示数据库出错。

    异常:
        sqlite3.Error: 数据库操作出错时引发。
    """
    try:
        namecard = session.get(NameCard, namecard_id)
        if not namecard:
            return 1
        namecard.isinrecycle = True
        session.add(namecard)
        session.commit()
        return 0
    except IntegrityError as e:
        session.rollback()
        print(f"修改数据时出错: {e}")
        return None

@auto_session
def restore_1_namecard(namecard_id: int, session:Session = None) -> int | None:
    """
    将单张名片从回收站恢复到正常状态。

    参数:
        user_id (int): 用户ID，用于验证用户权限。
        holder_id (int): 名片夹ID，指定名片所属的名片夹。
        namecard_id (int): 名片ID，指定需要恢复的名片。

    返回:
        int | None:
            0 表示恢复成功，
            1 表示名片不存在，
            None 表示数据库操作失败。
    """
    try:
        namecard = session.get(NameCard, namecard_id)
        if not namecard:
            return 1
        namecard.isinrecycle = False
        session.add(namecard)
        session.commit()
        return 0
    except IntegrityError as e:
        session.rollback()
        print(f"修改数据时出错: {e}")
        return None

@auto_session
def delete_1_namecard(namecard_id: int, session:Session = None) -> int | None:
    """
    将指定名片从数据库中删除。

    参数:
        user_id (int): 用户ID。
        holder_id (int): 名片夹ID。
        namecard_id (int): 名片ID。

    返回:
        int | None: 0表示删除成功，-1表示用户不存在，-2表示名片夹不存在，-3表示名片不存在，None表示操作失败。
    """
    namecard = session.get(NameCard, namecard_id)
    if not namecard:
        return -3
    try:
        session.delete(namecard)
        session.commit()
        return 0
    except IntegrityError as e:
        session.rollback()
        print(f"将名片从数据库中删除时出错: {e}")
        return None

@auto_session
def search_namecards_by_fields(holderid:int, keyword:str, fields:list[str], session:Session = None) -> list[dict[str, Any]] | None:
    """
    根据关键词查询名片

    参数:
        holderid (int): 名片夹ID
        keyword (str): 搜索关键词
        fields (list[str]): 要搜索的字段列表（如name, institution等）

    返回:
        list[dict[str, Any]] | None: 包含匹配名片的字典列表，未找到返回空列表，错误返回None
    """
    # 生成动态查询条件
    conditions = []
    for field in fields:
        if hasattr(NameCard, field):
            # 使用ilike进行不区分大小写的模糊匹配
            conditions.append(getattr(NameCard, field).ilike(f"%{keyword}%"))

    if not conditions:
        return []

    # 组合查询条件（OR逻辑）
    stmt = select(NameCard).where(
        NameCard.holder_id == holderid,
        NameCard.isinrecycle == False,
        or_(*conditions)
    )

    try:
        namecards = session.exec(stmt).all()
        return [n.to_dict() for n in namecards]
    except Exception as e:
        print(f"查询名片时发生错误: {e}")
        return None

